package com.collection;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class ArrayListSafe {

    public static void main(String[] args) {

//        listUnSafe();

//        safeList();

//        jucSafeList();
    }

    /**
     * 使用 juc 包中的 CopyOnWriteArrayList 来实现线程安全
     */
    private static void jucSafeList() {
        List<String> strs = new CopyOnWriteArrayList();

        for (int i = 0; i < 10; i++) {

            new Thread(()->{
                for (int j = 0; j < 100; j++) {

                    strs.add(UUID.randomUUID().toString().substring(0,10));
                }
                // modcount = exceptedmodcount
                System.out.println(strs);
            }).start();
        }

        while (Thread.activeCount() > 2){

            Thread.yield();
        }
    }

    /**
     *  解决方案1，使用 Collections 工具类，把 List 变成线程安全的集合，内部使用代理模式实现
     */
    private static void safeList() {

        List<String> strs = Collections.synchronizedList(new ArrayList<>());

        for (int i = 0; i < 10; i++) {

            new Thread(()->{
                for (int j = 0; j < 100; j++) {

                    strs.add(UUID.randomUUID().toString().substring(0,10));
                }
                // modcount = exceptedmodcount
                System.out.println(strs);
            }).start();
        }

        while (Thread.activeCount() > 2){

            Thread.yield();
        }
    }

    /**
     * 线程不安全，
     * 在调用 list的 toString() 方法进行输出list的集合是，toString内部会调用iterator遍历集合，
     * 每次获取集合中的一个值是，会比较iterator里面的exceptedModCount 与list集合中的modcount是否相同，
     * 如果不相同，则会抛出 ConcurrentModificationException
     *
     * modcont 在每次add，remove的函数调用了，进行增加
     */
    private static void listUnSafe() {
        ArrayList<String> strs =  new ArrayList<>();



        for (int i = 0; i < 10; i++) {

            new Thread(()->{
                for (int j = 0; j < 100; j++) {

                    strs.add(UUID.randomUUID().toString().substring(0,10));
                }
                // modcount = exceptedmodcount
                System.out.println(strs);
            }).start();
        }

        while (Thread.activeCount() > 2){

            Thread.yield();
        }
    }
}
